


/**
 * 获取成员值
 * @param target - 目标对象
 * @param propPath - 属性路径
 * @returns 成员值
 */
export function getMember(target:any, propPath:PropertyKey[]){
    
    if (propPath.length === 0) {
        return target;
    }

    for (let i = 0; i < propPath.length; i++) {
        if (target == undefined) {
            return undefined;
        }
        target = target[propPath[i]];
    }
    return target;
}



/**
 * 设置成员值
 * @remarks
 * 对于数字类型的路径，会使用数组作该属性所属的对象
 * @param target - 目标对象
 * @param propPath - 属性路径
 * @param value 
 */
export function setMember(target:any, propPath:PropertyKey[],value:any){
      
    if (propPath.length === 0) {
        Object.assign(target,value);
    }

    const max = propPath.length - 1 ;
    for (let i = 0; i < max; i++) {
        const prop = propPath[i];
        if (target[prop] == undefined) {
            target[prop] = typeof propPath[i+1] === "number" ? [] : {};
        }
        target = target[prop];
    }

    target[propPath[max]] = value;
}


/**
 * 获得默认值
 */
export type GetDefaultValue = ()=>any;


/**
 * 获取成员值
 * @param target 
 * @param propPath 
 * @param defaultValue 
 * @returns 
 */
export function getMemberWithDefault(target:any, propPath:PropertyKey[],defaultValue?:GetDefaultValue|any){
    
    const getDefaultValue = typeof defaultValue === "function" ? defaultValue : ()=>defaultValue ;
    let value = getMember(target, propPath);
    if (value === undefined) {
        value = getDefaultValue();
        setMember(target, propPath, value);
    }
    return value;
}


/**
 * 获取成员值
 * @param target 
 * @param propPath 
 * @param defaultValue 
 * @returns 如果 defaultValue 返回的是 Promise ，则该函数也返回 Promise，其它
 */
export function getMemberWithAsyncDefault(target:any, propPath:PropertyKey[],defaultValue?:GetDefaultValue|any){
    
    const getDefaultValue = typeof defaultValue === "function" ? defaultValue : ()=>defaultValue ;
    let value = getMember(target, propPath);
    if (value === undefined) {
        value = getDefaultValue();
        if (value instanceof Promise){
            value.then((v)=>setMember(target, propPath, v));
        }else {
            setMember(target, propPath, value);
        }
    }
    return value;
}





/**
 * 删除成员
 * @param target - 目标对象
 * @param propPath - 属性路径
 * @returns 是否执行了删除操作
 */
export function deleteMember(target:any, propPath:PropertyKey[]){
    
    if (propPath.length === 0) return true;
    
    const max = propPath.length - 1 ;
    for (let i = 0; i < max; i++) {
        if (target == undefined) return false;

        target = target[propPath[i]];
    }

    if (target == undefined) return false;
    return delete target[propPath[max]];
}










/**
 * 移除根级 undefined 属性
 * @param obj 
 * @returns 
 */
export function removeUndefined(obj:any){
    Object.keys(obj).forEach(key => obj[key] === undefined && delete obj[key]);
    return obj;
}

/**
 * 移除根级 undefined 和 null 属性
 * @param obj 
 * @returns 
 */
export function removeNull(obj:any){
    Object.keys(obj).forEach(key => obj[key] == null && delete obj[key]);
    return obj;
}

/**
 * 移除根级的属性值
 * @param obj 
 * @returns 
 */
export function removePropertyValues(obj:any,values:any[]){
    Object.keys(obj).forEach(key => values.includes(obj[key]) && delete obj[key]);
    return obj;
}

/**
 * 移除根级的空值属性
 * emptyValue 中包含的值是被认为是空值，除此之外还包括：空数组，也就是说无论 emptyValue 是什么，都会移除 空数组
 * @param obj 
 * @param emptyValue 自定义空值数组，默认值为 [undefined,null,""]
 * @returns 
 */
export function removeEmpty(obj:any,emptyValue?:any[]){
    emptyValue ??= [undefined,null,""];
    Object.keys(obj).forEach(key => {
        const value = obj[key];
        if (emptyValue.includes(value) || (Array.isArray(value) && value.length === 0)) delete obj[key];
    });
    return obj;
}







/**
 * 提取根级成员
 * @param obj 
 * @param keys 
 * @returns 返回一个只包含指定key的新对象
 */
export function pickMembers<Obj = any,Key extends keyof Obj = keyof Obj>(obj:Obj,keys:Key[]):Pick<Obj,Key>{
    const picked = {} as Pick<Obj,Key>;
    for (const key of keys){
        picked[key] = obj[key];
    }
    return picked;
}


/**
 * 剔除根级成员，删除根级成员
 * @remarks
 * 会改变原对象
 * @param obj 
 * @param keys 
 * @returns 返回原来的对象，但删除了指定的成员
 */
export function omitMembers<Obj = any,Key extends keyof Obj = keyof Obj>(obj:Obj,keys:Key[]):Omit<Obj,Key>{
    for (const key of keys){
        delete obj[key];
    }
    return obj;
}


/**
 * 通过属性路径提取成员
 * @param obj 
 * @param propPaths 
 * @returns 返回一个只包含指定key的新对象
 */
export function pickMembersByPath(obj:any,propPaths:PropertyKey[][]):any{
    const picked = {};
    for (const path of propPaths){
        const value = getMember(obj,path);
        setMember(picked,path,value);
    }
    return picked;
}


/**
 * 通过属性路径剔除成员，删除成员
 * @remarks
 * 会改变原对象
 * @param obj 
 * @param propPaths 
 * @returns 返回原来的对象，但删除了指定的成员
 */
export function omitMembersByPath(obj:any,propPaths:PropertyKey[][]):any{
    for (const path of propPaths){
        deleteMember(obj,path)
    }
    return obj;
}







/**
 *  将路径数组转成路径字符串
 * @remarks
 * 会自动将数组尾部的空值给移除，中间的空值转为占位符 placeholder
 * @param path 路径数组
 * @param separator 分隔符，默认是 "/"
 * @param placeholder 占位符，默认是 "-"
 * @returns 
 */
export function pathString(path:(string|number|null|undefined)[],separator?:string|null,placeholder?:string|null){
    separator ??= "/";
    placeholder ??= "-";
    for (let i = path.length - 1; i >= 0; i--){
        if (path[i] != null) break;
        path.length = i;
    }
    return path.map((item)=>item == null ? placeholder : item ).join(separator);
}





/**
 * 获取路径的第 index + 1 个部件
 * @param path - 路径字符串
 * @param index - 部件的索引
 * @param separator - 路径的分隔符
 * @returns 
 */
export function getPathPart(path:string,index:number,separator = "/"){
    const parts = path.split(separator,index+1);
    return parts[index];
}

/**
 * 替换路径部件
 * @param path - 路径
 * @param index - 被替换的部件的索引
 * @param replace - 替换的内容
 * @param separator - 路径的分隔符
 * @returns 
 */
export function replacePathPart(path:string,index:number,replace:string,separator = "/"){
    const parts = path.split(separator);
    parts[index] = replace;
    return parts.join(separator);
}



/**
 * 获取所有路径的第 index + 1 个的有效部件，会过滤掉为空的部件
 * @param paths - 路径字符串数组
 * @param index - 部件的索引
 * @param separator - 路径的分隔符
 * @returns 
 */
export function getValidPathParts(paths:string[],index:number,separator = "/"){
    const validParts:string[] = [];
    for (const path of paths){
        const part = path.split(separator,index+1)[index];
        if (part) validParts.push(part);
    }
    return validParts;
}
